home *** CD-ROM | disk | FTP | other *** search
/ Micromanía 92 / CDMM92_1.ISO / SOF 2 SDK / sof2sdk-101.msi / _92D6AC311BB48EBA344BBABC89DA6AB0 / _7405804FE31641409DD29C42C7282945 < prev    next >
Encoding:
Text File  |  2002-06-05  |  26.8 KB  |  1,151 lines

  1. // Copyright (C) 2001-2002 Raven Software.
  2. //
  3.  
  4. #include "g_local.h"
  5.  
  6. qboolean G_SpawnString( const char *key, const char *defaultString, char **out ) 
  7. {
  8.     int        i;
  9.  
  10.     if ( !level.spawning ) 
  11.     {
  12.         *out = (char *)defaultString;
  13.     }
  14.  
  15.     for ( i = 0 ; i < level.numSpawnVars ; i++ ) 
  16.     {
  17.         if ( !Q_stricmp( key, level.spawnVars[i][0] ) ) 
  18.         {
  19.             *out = level.spawnVars[i][1];
  20.             return qtrue;
  21.         }
  22.     }
  23.  
  24.     *out = (char *)defaultString;
  25.     return qfalse;
  26. }
  27.  
  28. qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out ) 
  29. {
  30.     char        *s;
  31.     qboolean    present;
  32.  
  33.     present = G_SpawnString( key, defaultString, &s );
  34.     *out = atof( s );
  35.     return present;
  36. }
  37.  
  38. qboolean G_SpawnInt( const char *key, const char *defaultString, int *out ) 
  39. {
  40.     char        *s;
  41.     qboolean    present;
  42.  
  43.     present = G_SpawnString( key, defaultString, &s );
  44.     *out = atoi( s );
  45.     return present;
  46. }
  47.  
  48. qboolean G_SpawnVector( const char *key, const char *defaultString, float *out ) 
  49. {
  50.     char        *s;
  51.     qboolean    present;
  52.  
  53.     present = G_SpawnString( key, defaultString, &s );
  54.     sscanf( s, "%f %f %f", &out[0], &out[1], &out[2] );
  55.     return present;
  56. }
  57.  
  58.  
  59.  
  60. //
  61. // fields are needed for spawning from the entity string
  62. //
  63. typedef enum 
  64. {
  65.     F_INT, 
  66.     F_FLOAT,
  67.     F_LSTRING,            // string on disk, pointer in memory, TAG_LEVEL
  68.     F_GSTRING,            // string on disk, pointer in memory, TAG_GAME
  69.     F_VECTOR,
  70.     F_ANGLEHACK,
  71.     F_ENTITY,            // index on disk, pointer in memory
  72.     F_ITEM,                // index on disk, pointer in memory
  73.     F_CLIENT,            // index on disk, pointer in memory
  74.     F_IGNORE
  75.  
  76. } fieldtype_t;
  77.  
  78. typedef struct
  79. {
  80.     char*        name;
  81.     int            ofs;
  82.     fieldtype_t    type;
  83.     int            flags;
  84.  
  85. } field_t;
  86.  
  87. field_t fields[] = 
  88. {
  89.     {"classname",            FOFS(classname),            F_LSTRING},
  90.     {"origin",                FOFS(s.origin),                F_VECTOR},
  91.     {"model",                FOFS(model),                F_LSTRING},
  92.     {"model2",                FOFS(model2),                F_LSTRING},
  93.     {"spawnflags",            FOFS(spawnflags),            F_INT},
  94.     {"speed",                FOFS(speed),                F_FLOAT},
  95.     {"target",                FOFS(target),                F_LSTRING},
  96.     {"targetname",            FOFS(targetname),            F_LSTRING},
  97.     {"message",                FOFS(message),                F_LSTRING},
  98.     {"team",                FOFS(team),                    F_LSTRING},
  99.     {"wait",                FOFS(wait),                    F_FLOAT},
  100.     {"random",                FOFS(random),                F_FLOAT},
  101.     {"count",                FOFS(count),                F_INT},
  102.     {"health",                FOFS(health),                F_INT},
  103.     {"light",                0,                            F_IGNORE},
  104.     {"dmg",                    FOFS(damage),                F_INT},
  105.     {"angles",                FOFS(s.angles),                F_VECTOR},
  106.     {"angle",                FOFS(s.angles),                F_ANGLEHACK},
  107.     {"targetShaderName",    FOFS(targetShaderName),        F_LSTRING},
  108.     {"targetShaderNewName", FOFS(targetShaderNewName),    F_LSTRING},
  109.  
  110.     {NULL}
  111. };
  112.  
  113.  
  114. typedef struct 
  115. {
  116.     char    *name;
  117.     void    (*spawn)(gentity_t *ent);
  118.  
  119. } spawn_t;
  120.  
  121. void SP_info_player_deathmatch        (gentity_t *ent);
  122. void SP_info_player_intermission    (gentity_t *ent);
  123.  
  124. void SP_func_plat                    (gentity_t *ent);
  125. void SP_func_static                    (gentity_t *ent);
  126. void SP_func_rotating                (gentity_t *ent);
  127. void SP_func_bobbing                (gentity_t *ent);
  128. void SP_func_pendulum                (gentity_t *ent);
  129. void SP_func_button                    (gentity_t *ent);
  130. void SP_func_door                    (gentity_t *ent);
  131. void SP_func_train                    (gentity_t *ent);
  132. void SP_func_timer                    (gentity_t *ent);
  133. void SP_func_glass                    (gentity_t *ent);
  134. void SP_func_wall                    (gentity_t *ent);
  135.  
  136. void SP_trigger_always                (gentity_t *ent);
  137. void SP_trigger_multiple            (gentity_t *ent);
  138. void SP_trigger_push                (gentity_t *ent);
  139. void SP_trigger_teleport            (gentity_t *ent);
  140. void SP_trigger_hurt                (gentity_t *ent);
  141. void SP_trigger_ladder                (gentity_t *ent);
  142.  
  143. void SP_target_give                    (gentity_t *ent);
  144. void SP_target_delay                (gentity_t *ent);
  145. void SP_target_speaker                (gentity_t *ent);
  146. void SP_target_print                (gentity_t *ent);
  147. void SP_target_laser                (gentity_t *ent);
  148. void SP_target_score                (gentity_t *ent);
  149. void SP_target_teleporter            (gentity_t *ent);
  150. void SP_target_relay                (gentity_t *ent);
  151. void SP_target_kill                    (gentity_t *ent);
  152. void SP_target_position                (gentity_t *ent);
  153. void SP_target_location                (gentity_t *ent);
  154. void SP_target_push                    (gentity_t *ent);
  155. void SP_target_effect                (gentity_t *ent);
  156.  
  157. void SP_info_notnull                (gentity_t *ent);
  158. void SP_info_camp                    (gentity_t *ent);
  159. void SP_path_corner                    (gentity_t *ent);
  160.  
  161. void SP_misc_teleporter_dest        (gentity_t *ent);
  162. void SP_misc_model                    (gentity_t *ent);
  163. void SP_misc_G2model                (gentity_t *ent);
  164. void SP_misc_portal_camera            (gentity_t *ent);
  165. void SP_misc_portal_surface            (gentity_t *ent);
  166. void SP_misc_bsp                    (gentity_t *ent);
  167. void SP_terrain                        (gentity_t *ent);
  168.  
  169. void SP_model_static                (gentity_t* ent);
  170.  
  171. void SP_gametype_item                (gentity_t* ent);
  172. void SP_gametype_trigger            (gentity_t* ent);
  173. void SP_gametype_player                (gentity_t* ent);
  174. void SP_mission_player                (gentity_t* ent);
  175.                                     
  176. void SP_fx_play_effect                (gentity_t* ent);
  177.  
  178. spawn_t    spawns[] = 
  179. {
  180.     // info entities don't do anything at all, but provide positional
  181.     // information for things controlled by other processes
  182.     {"info_player_deathmatch",        SP_info_player_deathmatch},
  183.     {"info_player_intermission",    SP_info_player_intermission},
  184.     {"info_notnull",                SP_info_notnull},        // use target_position instead
  185.  
  186.     {"func_plat",                    SP_func_plat},
  187.     {"func_button",                    SP_func_button},
  188.     {"func_door",                    SP_func_door},
  189.     {"func_static",                    SP_func_static},
  190.     {"func_rotating",                SP_func_rotating},
  191.     {"func_bobbing",                SP_func_bobbing},
  192.     {"func_pendulum",                SP_func_pendulum},
  193.     {"func_train",                    SP_func_train},
  194.     {"func_timer",                    SP_func_timer},
  195.     {"func_glass",                    SP_func_glass},
  196.     {"func_wall",                    SP_func_wall},
  197.  
  198.     // Triggers are brush objects that cause an effect when contacted
  199.     // by a living player, usually involving firing targets.
  200.     // While almost everything could be done with
  201.     // a single trigger class and different targets, triggered effects
  202.     // could not be client side predicted (push and teleport).
  203.     {"trigger_always",                SP_trigger_always},
  204.     {"trigger_multiple",            SP_trigger_multiple},
  205.     {"trigger_push",                SP_trigger_push},
  206.     {"trigger_teleport",            SP_trigger_teleport},
  207.     {"trigger_hurt",                SP_trigger_hurt},
  208.     {"trigger_ladder",                SP_trigger_ladder },
  209.  
  210.     // targets perform no action by themselves, but must be triggered
  211.     // by another entity
  212.     {"target_give",                    SP_target_give},
  213.     {"target_delay",                SP_target_delay},
  214.     {"target_speaker",                SP_target_speaker},
  215.     {"target_print",                SP_target_print},
  216.     {"target_laser",                SP_target_laser},
  217.     {"target_score",                SP_target_score},
  218.     {"target_teleporter",            SP_target_teleporter},
  219.     {"target_relay",                SP_target_relay},
  220.     {"target_kill",                    SP_target_kill},
  221.     {"target_position",                SP_target_position},
  222.     {"target_location",                SP_target_location},
  223.     {"target_push",                    SP_target_push},
  224.     {"target_effect",                SP_target_effect},
  225.  
  226.     {"path_corner",                    SP_path_corner},
  227.  
  228.     {"misc_teleporter_dest",        SP_misc_teleporter_dest},
  229.     {"misc_model",                    SP_misc_model},
  230.     {"client_model",                SP_model_static},
  231.     {"misc_G2model",                SP_misc_G2model},
  232.     {"misc_portal_surface",            SP_misc_portal_surface},
  233.     {"misc_portal_camera",            SP_misc_portal_camera},
  234.     {"misc_bsp",                    SP_misc_bsp},
  235.     {"terrain",                        SP_terrain},
  236.  
  237.     {"model_static",                SP_model_static },
  238.  
  239.     {"gametype_item",                SP_gametype_item },
  240.     {"gametype_trigger",            SP_gametype_trigger },
  241.     {"gametype_player",                SP_gametype_player },
  242.     {"mission_player",                SP_mission_player },
  243.  
  244.     // stuff from SP emulated
  245.     {"func_breakable_brush",        SP_func_static},
  246.     {"fx_play_effect",                SP_fx_play_effect},
  247.  
  248.     // The following classnames are instantly removed when spawned.  The RMG 
  249.     // shares instances with single player which is what causes these things
  250.     // to attempt to spawn
  251.     {"light",                        0},
  252.     {"func_group",                    0},
  253.     {"info_camp",                    0},
  254.     {"info_null",                    0},
  255.     {"door_rotating",                0},
  256.     {"emplaced_wpn",                0},
  257.     {"info_NPC*",                    0},
  258.     {"info_player_start",            0},
  259.     {"NPC_*",                        0},
  260.     {"ce_*",                        0},
  261.     {"pickup_ammo",                    0},
  262.     {"script_runner",                0},
  263.     {"trigger_arioche_objective",    0},
  264.  
  265.     {0, 0}
  266. };
  267.  
  268. /*
  269. ===============
  270. G_CallSpawn
  271.  
  272. Finds the spawn function for the entity and calls it,
  273. returning qfalse if not found
  274. ===============
  275. */
  276. qboolean G_CallSpawn( gentity_t *ent ) 
  277. {
  278.     spawn_t    *s;
  279.     gitem_t    *item;
  280.  
  281.     if ( !ent->classname ) 
  282.     {
  283.         Com_Printf ("G_CallSpawn: NULL classname\n");
  284.         return qfalse;
  285.     }
  286.  
  287.     // check item spawn functions
  288.     for ( item=bg_itemlist+1 ; item->classname ; item++ ) 
  289.     {
  290.         if ( !strcmp(item->classname, ent->classname) ) 
  291.         {
  292.             // If this is a backpack then handle it specially
  293.             if ( item->giType == IT_BACKPACK )
  294.             {
  295.                 if ( !level.gametypeData->backpack )
  296.                 {
  297.                     return qfalse;
  298.                 }
  299.  
  300.                 G_SpawnItem ( ent, item );
  301.                 return qtrue;
  302.             }
  303.  
  304.             // Make sure pickups arent disabled
  305.             if ( !level.pickupsDisabled )
  306.             {
  307.                 G_SpawnItem( ent, item );
  308.                 return qtrue;
  309.             }
  310.             else
  311.             {    // Pickups dont spawn when disabled - this avoids the "doesn't have a spawn function" message
  312.                 return qfalse;
  313.             }
  314.         }
  315.     }
  316.  
  317.     // check normal spawn functions
  318.     for ( s=spawns ; s->name ; s++ ) 
  319.     {
  320.         char* wildcard = strchr ( s->name, '*' );
  321.         int   result;
  322.         
  323.         if ( wildcard )
  324.         {
  325.             result = Q_strncmp ( s->name, ent->classname, wildcard - s->name );
  326.         }
  327.         else
  328.         {
  329.             result = strcmp(s->name, ent->classname);
  330.         }
  331.  
  332.         if ( !result ) 
  333.         {
  334.             if (s->spawn)
  335.             {    // found it
  336.                 s->spawn(ent);
  337.                 return qtrue;
  338.             }
  339.             else
  340.             {
  341.                 return qfalse;
  342.             }
  343.         }
  344.     }
  345.     
  346.     Com_Printf ("%s doesn't have a spawn function\n", ent->classname);
  347.     return qfalse;
  348. }
  349.  
  350. /*
  351. =============
  352. G_NewString
  353.  
  354. Builds a copy of the string, translating \n to real linefeeds
  355. so message texts can be multi-line
  356. =============
  357. */
  358. char *G_NewString( const char *string ) 
  359. {
  360.     char    *newb, *new_p;
  361.     int        i,l;
  362.     
  363.     l = strlen(string) + 1;
  364.  
  365.     newb = trap_VM_LocalAlloc( l );
  366.  
  367.     new_p = newb;
  368.  
  369.     // turn \n into a real linefeed
  370.     for ( i=0 ; i< l ; i++ ) {
  371.         if (string[i] == '\\' && i < l-1) {
  372.             i++;
  373.             if (string[i] == 'n') {
  374.                 *new_p++ = '\n';
  375.             } else {
  376.                 *new_p++ = '\\';
  377.             }
  378.         } else {
  379.             *new_p++ = string[i];
  380.         }
  381.     }
  382.     
  383.     return newb;
  384. }
  385.  
  386. /*
  387. ===============
  388. G_ParseField
  389.  
  390. Takes a key/value pair and sets the binary values
  391. in a gentity
  392. ===============
  393. */
  394. void G_ParseField( const char *key, const char *value, gentity_t *ent ) {
  395.     field_t    *f;
  396.     byte    *b;
  397.     float    v;
  398.     vec3_t    vec;
  399.  
  400.     for ( f=fields ; f->name ; f++ ) {
  401.         if ( !Q_stricmp(f->name, key) ) {
  402.             // found it
  403.             b = (byte *)ent;
  404.  
  405.             switch( f->type ) {
  406.             case F_LSTRING:
  407.                 *(char **)(b+f->ofs) = G_NewString (value);
  408.                 break;
  409.             case F_VECTOR:
  410.                 sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
  411.                 ((float *)(b+f->ofs))[0] = vec[0];
  412.                 ((float *)(b+f->ofs))[1] = vec[1];
  413.                 ((float *)(b+f->ofs))[2] = vec[2];
  414.                 break;
  415.             case F_INT:
  416.                 *(int *)(b+f->ofs) = atoi(value);
  417.                 break;
  418.             case F_FLOAT:
  419.                 *(float *)(b+f->ofs) = atof(value);
  420.                 break;
  421.             case F_ANGLEHACK:
  422.                 v = atof(value);
  423.                 ((float *)(b+f->ofs))[0] = 0;
  424.                 ((float *)(b+f->ofs))[1] = v;
  425.                 ((float *)(b+f->ofs))[2] = 0;
  426.                 break;
  427.             default:
  428.             case F_IGNORE:
  429.                 break;
  430.             }
  431.             return;
  432.         }
  433.     }
  434. }
  435.  
  436. /*
  437. ===================
  438. G_IsGametypeInList
  439.  
  440. Determines if the given gametype is in the given list.
  441. ===================
  442. */
  443. qboolean G_IsGametypeInList ( const char* gametype, const char* list )
  444. {
  445.     const char* buf = (char*) list;
  446.     char* token;
  447.  
  448.     while ( 1 )
  449.     {
  450.         token = COM_Parse ( &buf );
  451.         if ( !token || !token[0] )
  452.         {
  453.             break;
  454.         }
  455.  
  456.         if ( Q_stricmp ( token, gametype ) == 0 )
  457.         {
  458.             return qtrue;
  459.         }
  460.     }
  461.  
  462.     return qfalse;
  463. }    
  464.  
  465. /*
  466. ===================
  467. G_SpawnGEntityFromSpawnVars
  468.  
  469. Spawn an entity and fill in all of the level fields from
  470. level.spawnVars[], then call the class specfic spawn function
  471. ===================
  472. */
  473. void G_SpawnGEntityFromSpawnVars( qboolean inSubBSP ) 
  474. {
  475.     int            i;
  476.     gentity_t    *ent;
  477.     char        *value;
  478.  
  479.     if (inSubBSP)
  480.     {    
  481.         // filter out the unwanted entities
  482.         G_SpawnString("filter", "", &value);
  483.         if (value[0] && Q_stricmp(level.mFilter, value))
  484.         {    
  485.             // we are not matching up to the filter, so no spawney
  486.             return;
  487.         }
  488.     }
  489.  
  490.     // get the next free entity
  491.     ent = G_Spawn();
  492.  
  493.     for ( i = 0 ; i < level.numSpawnVars ; i++ ) 
  494.     {
  495.         G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent );
  496.     }
  497.  
  498.     // check for "notteam" flag (GT_DM)
  499.     if ( level.gametypeData->teams ) 
  500.     {
  501.         G_SpawnInt( "notteam", "0", &i );
  502.         if ( i ) 
  503.         {
  504.             G_FreeEntity( ent );
  505.             return;
  506.         }
  507.     } 
  508.     else 
  509.     {
  510.         G_SpawnInt( "notfree", "0", &i );
  511.         if ( i ) 
  512.         {
  513.             G_FreeEntity( ent );
  514.             return;
  515.         }
  516.     }
  517.  
  518.     // Only spawn this entity in the specified gametype
  519.     if( G_SpawnString( "gametype", NULL, &value ) && value ) 
  520.     {
  521.         if ( !G_IsGametypeInList ( level.gametypeData->name, value ) )
  522.         {
  523.             if ( level.gametypeData->basegametype )
  524.             {
  525.                 if ( !G_IsGametypeInList ( level.gametypeData->basegametype, value ) )
  526.                 {
  527.                     G_FreeEntity ( ent );
  528.                     return;
  529.                 }
  530.             }
  531.             else
  532.             {
  533.                 G_FreeEntity ( ent );
  534.                 return;
  535.             }
  536.         } 
  537.     }
  538.  
  539.     // move editor origin to pos
  540.     VectorCopy( ent->s.origin, ent->s.pos.trBase );
  541.     VectorCopy( ent->s.origin, ent->r.currentOrigin );
  542.  
  543.     // if we didn't get a classname, don't bother spawning anything
  544.     if ( !G_CallSpawn( ent ) ) 
  545.     {
  546.         G_FreeEntity( ent );
  547.     }
  548. }
  549.  
  550.  
  551.  
  552. /*
  553. ====================
  554. G_AddSpawnVarToken
  555. ====================
  556. */
  557. char *G_AddSpawnVarToken( const char *string ) 
  558. {
  559.     int        l;
  560.     char    *dest;
  561.  
  562.     l = strlen( string );
  563.     if ( level.numSpawnVarChars + l + 1 > MAX_SPAWN_VARS_CHARS ) 
  564.     {
  565.         Com_Error( ERR_FATAL, "G_AddSpawnVarToken: MAX_SPAWN_CHARS" );
  566.     }
  567.  
  568.     dest = level.spawnVarChars + level.numSpawnVarChars;
  569.     memcpy( dest, string, l+1 );
  570.  
  571.     level.numSpawnVarChars += l + 1;
  572.  
  573.     return dest;
  574. }
  575.  
  576. void AddSpawnField(char *field, char *value)
  577. {
  578.     int    i;
  579.  
  580.     for(i=0;i<level.numSpawnVars;i++)
  581.     {
  582.         if (Q_stricmp(level.spawnVars[i][0], field) == 0)
  583.         {
  584.             level.spawnVars[ i ][1] = G_AddSpawnVarToken( value );
  585.             return;
  586.         }
  587.     }
  588.  
  589.     level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( field );
  590.     level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( value );
  591.     level.numSpawnVars++;
  592. }
  593.  
  594. #define NOVALUE "novalue"
  595.  
  596. static void HandleEntityAdjustment(void)
  597. {
  598.     char        *value;
  599.     vec3_t        origin, newOrigin, angles;
  600.     char        temp[MAX_QPATH];
  601.     float        rotation;
  602.  
  603.     G_SpawnString("origin", NOVALUE, &value);
  604.     if (Q_stricmp(value, NOVALUE) != 0)
  605.     {
  606.         sscanf( value, "%f %f %f", &origin[0], &origin[1], &origin[2] );
  607.     }
  608.     else
  609.     {
  610.         origin[0] = origin[1] = origin[2] = 0.0;
  611.     }
  612.  
  613.     rotation = DEG2RAD(level.mRotationAdjust);
  614.     newOrigin[0] = origin[0]*cos(rotation) - origin[1]*sin(rotation);
  615.     newOrigin[1] = origin[0]*sin(rotation) + origin[1]*cos(rotation);
  616.     newOrigin[2] = origin[2];
  617.     VectorAdd(newOrigin, level.mOriginAdjust, newOrigin);
  618.     // damn VMs don't handle outputing a float that is compatible with sscanf in all cases
  619.     Com_sprintf(temp, MAX_QPATH, "%0.0f %0.0f %0.0f", newOrigin[0], newOrigin[1], newOrigin[2]);
  620.     AddSpawnField("origin", temp);
  621.  
  622.     G_SpawnString("angles", NOVALUE, &value);
  623.     if (Q_stricmp(value, NOVALUE) != 0)
  624.     {
  625.         sscanf( value, "%f %f %f", &angles[0], &angles[1], &angles[2] );
  626.  
  627.         angles[1] = fmod(angles[1] + level.mRotationAdjust, 360.0);
  628.         // damn VMs don't handle outputing a float that is compatible with sscanf in all cases
  629.         Com_sprintf(temp, MAX_QPATH, "%0.0f %0.0f %0.0f", angles[0], angles[1], angles[2]);
  630.         AddSpawnField("angles", temp);
  631.     }
  632.     else
  633.     {
  634.         G_SpawnString("angle", NOVALUE, &value);
  635.         if (Q_stricmp(value, NOVALUE) != 0)
  636.         {
  637.             sscanf( value, "%f", &angles[1] );
  638.         }
  639.         else
  640.         {
  641.             angles[1] = 0.0;
  642.         }
  643.         angles[1] = fmod(angles[1] + level.mRotationAdjust, 360.0);
  644.         Com_sprintf(temp, MAX_QPATH, "%0.0f", angles[1]);
  645.         AddSpawnField("angle", temp);
  646.     }
  647.  
  648.     // RJR experimental code for handling "direction" field of breakable brushes
  649.     // though direction is rarely ever used.
  650.     G_SpawnString("direction", NOVALUE, &value);
  651.     if (Q_stricmp(value, NOVALUE) != 0)
  652.     {
  653.         sscanf( value, "%f %f %f", &angles[0], &angles[1], &angles[2] );
  654.     }
  655.     else
  656.     {
  657.         angles[0] = angles[1] = angles[2] = 0.0;
  658.     }
  659.     angles[1] = fmod(angles[1] + level.mRotationAdjust, 360.0);
  660.     Com_sprintf(temp, MAX_QPATH, "%0.0f %0.0f %0.0f", angles[0], angles[1], angles[2]);
  661.     AddSpawnField("direction", temp);
  662.  
  663.  
  664.     AddSpawnField("BSPInstanceID", level.mTargetAdjust);
  665.  
  666.     G_SpawnString("targetname", NOVALUE, &value);
  667.     if (Q_stricmp(value, NOVALUE) != 0)
  668.     {
  669.         Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
  670.         AddSpawnField("targetname", temp);
  671.     }
  672.  
  673.     G_SpawnString("target", NOVALUE, &value);
  674.     if (Q_stricmp(value, NOVALUE) != 0)
  675.     {
  676.         Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
  677.         AddSpawnField("target", temp);
  678.     }
  679.  
  680.     G_SpawnString("killtarget", NOVALUE, &value);
  681.     if (Q_stricmp(value, NOVALUE) != 0)
  682.     {
  683.         Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
  684.         AddSpawnField("killtarget", temp);
  685.     }
  686.  
  687.     G_SpawnString("brushparent", NOVALUE, &value);
  688.     if (Q_stricmp(value, NOVALUE) != 0)
  689.     {
  690.         Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
  691.         AddSpawnField("brushparent", temp);
  692.     }
  693.  
  694.     G_SpawnString("brushchild", NOVALUE, &value);
  695.     if (Q_stricmp(value, NOVALUE) != 0)
  696.     {
  697.         Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
  698.         AddSpawnField("brushchild", temp);
  699.     }
  700.  
  701.     G_SpawnString("enemy", NOVALUE, &value);
  702.     if (Q_stricmp(value, NOVALUE) != 0)
  703.     {
  704.         Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
  705.         AddSpawnField("enemy", temp);
  706.     }
  707.  
  708.     G_SpawnString("ICARUSname", NOVALUE, &value);
  709.     if (Q_stricmp(value, NOVALUE) != 0)
  710.     {
  711.         Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
  712.         AddSpawnField("ICARUSname", temp);
  713.     }
  714. }
  715.  
  716. /*
  717. ====================
  718. G_ParseSpawnVars
  719.  
  720. Parses a brace bounded set of key / value pairs out of the
  721. level's entity strings into level.spawnVars[]
  722.  
  723. This does not actually spawn an entity.
  724. ====================
  725. */
  726. qboolean G_ParseSpawnVars( qboolean inSubBSP ) 
  727. {
  728.     char    keyname[MAX_TOKEN_CHARS];
  729.     char    com_token[MAX_TOKEN_CHARS];
  730.  
  731.     level.numSpawnVars = 0;
  732.     level.numSpawnVarChars = 0;
  733.  
  734.     // parse the opening brace
  735.     if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) 
  736.     {
  737.         // end of spawn string
  738.         return qfalse;
  739.     }
  740.     
  741.     if ( com_token[0] != '{' ) 
  742.     {
  743.         Com_Error( ERR_FATAL, "G_ParseSpawnVars: found %s when expecting {",com_token );
  744.     }
  745.  
  746.     // go through all the key / value pairs
  747.     while ( 1 ) 
  748.     {
  749.         // parse key
  750.         if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) 
  751.         {
  752.             Com_Error( ERR_FATAL, "G_ParseSpawnVars: EOF without closing brace" );
  753.         }
  754.  
  755.         if ( keyname[0] == '}' ) 
  756.         {
  757.             break;
  758.         }
  759.         
  760.         // parse value    
  761.         if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) 
  762.         {
  763.             Com_Error( ERR_FATAL, "G_ParseSpawnVars: EOF without closing brace" );
  764.         }
  765.  
  766.         if ( com_token[0] == '}' ) 
  767.         {
  768.             Com_Error( ERR_FATAL, "G_ParseSpawnVars: closing brace without data" );
  769.         }
  770.         
  771.         if ( level.numSpawnVars == MAX_SPAWN_VARS ) 
  772.         {
  773.             Com_Error( ERR_FATAL, "G_ParseSpawnVars: MAX_SPAWN_VARS" );
  774.         }
  775.         
  776.         AddSpawnField(keyname, com_token);
  777.     }
  778.  
  779.     if (inSubBSP)
  780.     {
  781.         HandleEntityAdjustment();
  782.     }
  783.  
  784.     return qtrue;
  785. }
  786.  
  787. static char *defaultStyles[32][3] = 
  788. {
  789.     {    // 0 normal
  790.         "z",
  791.         "z",
  792.         "z"
  793.     },
  794.     {    // 1 FLICKER (first variety)
  795.         "mmnmmommommnonmmonqnmmo",
  796.         "mmnmmommommnonmmonqnmmo",
  797.         "mmnmmommommnonmmonqnmmo"
  798.     },
  799.     {    // 2 SLOW STRONG PULSE
  800.         "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcb",
  801.         "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcb",
  802.         "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcb"
  803.     },
  804.     {    // 3 CANDLE (first variety)
  805.         "mmmmmaaaaammmmmaaaaaabcdefgabcdefg",
  806.         "mmmmmaaaaammmmmaaaaaabcdefgabcdefg",
  807.         "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"
  808.     },
  809.     {    // 4 FAST STROBE
  810.         "mamamamamama",
  811.         "mamamamamama",
  812.         "mamamamamama"
  813.     },
  814.     {    // 5 GENTLE PULSE 1
  815.         "jklmnopqrstuvwxyzyxwvutsrqponmlkj",
  816.         "jklmnopqrstuvwxyzyxwvutsrqponmlkj",
  817.         "jklmnopqrstuvwxyzyxwvutsrqponmlkj"
  818.     },
  819.     {    // 6 FLICKER (second variety)
  820.         "nmonqnmomnmomomno",
  821.         "nmonqnmomnmomomno",
  822.         "nmonqnmomnmomomno"
  823.     },
  824.     {    // 7 CANDLE (second variety)
  825.         "mmmaaaabcdefgmmmmaaaammmaamm",
  826.         "mmmaaaabcdefgmmmmaaaammmaamm",
  827.         "mmmaaaabcdefgmmmmaaaammmaamm"
  828.     },
  829.     {    // 8 CANDLE (third variety)
  830.         "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa",
  831.         "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa",
  832.         "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"
  833.     },
  834.     {    // 9 SLOW STROBE (fourth variety)
  835.         "aaaaaaaazzzzzzzz",
  836.         "aaaaaaaazzzzzzzz",
  837.         "aaaaaaaazzzzzzzz"
  838.     },
  839.     {    // 10 FLUORESCENT FLICKER
  840.         "mmamammmmammamamaaamammma",
  841.         "mmamammmmammamamaaamammma",
  842.         "mmamammmmammamamaaamammma"
  843.     },
  844.     {    // 11 SLOW PULSE NOT FADE TO BLACK
  845.         "abcdefghijklmnopqrrqponmlkjihgfedcba",
  846.         "abcdefghijklmnopqrrqponmlkjihgfedcba",
  847.         "abcdefghijklmnopqrrqponmlkjihgfedcba"
  848.     },
  849.     {    // 12 FAST PULSE FOR JEREMY
  850.         "mkigegik",
  851.         "mkigegik",
  852.         "mkigegik"
  853.     },
  854.     {    // 13 Test Blending
  855.         "abcdefghijklmqrstuvwxyz",
  856.         "zyxwvutsrqmlkjihgfedcba",
  857.         "aammbbzzccllcckkffyyggp"
  858.     },
  859.     {    // 14
  860.         "",
  861.         "",
  862.         ""
  863.     },
  864.     {    // 15
  865.         "",
  866.         "",
  867.         ""
  868.     },
  869.     {    // 16
  870.         "",
  871.         "",
  872.         ""
  873.     },
  874.     {    // 17
  875.         "",
  876.         "",
  877.         ""
  878.     },
  879.     {    // 18
  880.         "",
  881.         "",
  882.         ""
  883.     },
  884.     {    // 19
  885.         "",
  886.         "",
  887.         ""
  888.     },
  889.     {    // 20
  890.         "",
  891.         "",
  892.         ""
  893.     },
  894.     {    // 21
  895.         "",
  896.         "",
  897.         ""
  898.     },
  899.     {    // 22
  900.         "",
  901.         "",
  902.         ""
  903.     },
  904.     {    // 23
  905.         "",
  906.         "",
  907.         ""
  908.     },
  909.     {    // 24
  910.         "",
  911.         "",
  912.         ""
  913.     },
  914.     {    // 25
  915.         "",
  916.         "",
  917.         ""
  918.     },
  919.     {    // 26
  920.         "",
  921.         "",
  922.         ""
  923.     },
  924.     {    // 27
  925.         "",
  926.         "",
  927.         ""
  928.     },
  929.     {    // 28
  930.         "",
  931.         "",
  932.         ""
  933.     },
  934.     {    // 29
  935.         "",
  936.         "",
  937.         ""
  938.     },
  939.     {    // 30
  940.         "",
  941.         "",
  942.         ""
  943.     },
  944.     {    // 31
  945.         "",
  946.         "",
  947.         ""
  948.     }
  949. };
  950.  
  951. qboolean SP_bsp_worldspawn ( void )
  952. {
  953.     return qtrue;
  954. }
  955.  
  956. /*QUAKED worldspawn (0 0 0) ?
  957.  
  958. Every map should have exactly one worldspawn.
  959. "music"            music wav file
  960. "soundSet"        soundset name to use (do not combine with 'noise', ignores all other flags)
  961. "gravity"        800 is default gravity
  962. "message"        Text to print during connection process
  963. "mission"        Indicates which mission script file should be used to find the scripts for mission mode
  964. */
  965. void SP_worldspawn( void ) 
  966. {
  967.     char        *text, temp[32];
  968.     int            i;
  969.     int            lengthRed, lengthBlue, lengthGreen;
  970.  
  971.     G_SpawnString( "classname", "", &text );
  972.     if ( Q_stricmp( text, "worldspawn" ) ) 
  973.     {
  974.         Com_Error( ERR_FATAL, "SP_worldspawn: The first entity isn't 'worldspawn'" );
  975.     }
  976.  
  977.     // make some data visible to connecting client
  978.     trap_SetConfigstring( CS_GAME_VERSION, GAME_VERSION );
  979.  
  980.     trap_SetConfigstring( CS_LEVEL_START_TIME, va("%i", level.startTime ) );
  981.  
  982.     G_SpawnString( "music", "", &text );
  983.     trap_SetConfigstring( CS_MUSIC, text );
  984.  
  985.     if (G_SpawnString( "soundSet", "", &text ) )
  986.     {
  987.         trap_SetConfigstring(CS_AMBIENT_SOUNDSETS, text );
  988.     }
  989.  
  990.     if ( level.gametypeData->teams )
  991.     {
  992.         G_SpawnString( "redteam", "", &text );
  993.         if ( text && *text )
  994.         {
  995.             level.gametypeTeam[TEAM_RED] = trap_VM_LocalStringAlloc ( text );
  996.         }
  997.  
  998.         G_SpawnString( "blueteam", "", &text );
  999.         if ( text && *text )
  1000.         {
  1001.             level.gametypeTeam[TEAM_BLUE] = trap_VM_LocalStringAlloc ( text );
  1002.         }
  1003.  
  1004.         if ( !level.gametypeTeam[TEAM_RED]  ||
  1005.              !level.gametypeTeam[TEAM_BLUE]    )
  1006.         {
  1007.             level.gametypeTeam[TEAM_RED] = "marine";
  1008.             level.gametypeTeam[TEAM_BLUE] = "thug";
  1009.         }
  1010.  
  1011.         trap_SetConfigstring( CS_GAMETYPE_REDTEAM, level.gametypeTeam[TEAM_RED] );
  1012.         trap_SetConfigstring( CS_GAMETYPE_BLUETEAM, level.gametypeTeam[TEAM_BLUE] );
  1013.     }
  1014.  
  1015.     G_SpawnString( "message", "", &text );
  1016.     trap_SetConfigstring( CS_MESSAGE, text );                // map specific message
  1017.  
  1018.     trap_SetConfigstring( CS_MOTD, g_motd.string );        // message of the day
  1019.  
  1020.     G_SpawnString( "gravity", "800", &text );
  1021.     trap_Cvar_Set( "g_gravity", text );
  1022.  
  1023.     // Handle all the worldspawn stuff common to both main bsp and sub bsp
  1024.     SP_bsp_worldspawn ( );
  1025.  
  1026.     g_entities[ENTITYNUM_WORLD].s.number = ENTITYNUM_WORLD;
  1027.     g_entities[ENTITYNUM_WORLD].classname = "worldspawn";
  1028.  
  1029.     // see if we want a warmup time
  1030.     trap_SetConfigstring( CS_WARMUP, "" );
  1031.     if ( g_restarted.integer ) 
  1032.     {
  1033.         trap_Cvar_Set( "g_restarted", "0" );
  1034.         level.warmupTime = 0;
  1035.     } 
  1036.     else if ( g_doWarmup.integer ) 
  1037.     { 
  1038.         // Turn it on
  1039.         level.warmupTime = -1;
  1040.         trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
  1041.         G_LogPrintf( "Warmup:\n" );
  1042.     }
  1043.  
  1044.     trap_SetConfigstring(CS_LIGHT_STYLES+(LS_STYLES_START*3)+0, defaultStyles[0][0]);
  1045.     trap_SetConfigstring(CS_LIGHT_STYLES+(LS_STYLES_START*3)+1, defaultStyles[0][1]);
  1046.     trap_SetConfigstring(CS_LIGHT_STYLES+(LS_STYLES_START*3)+2, defaultStyles[0][2]);
  1047.     
  1048.     for(i=1;i<LS_NUM_STYLES;i++)
  1049.     {
  1050.         Com_sprintf(temp, sizeof(temp), "ls_%dr", i);
  1051.         G_SpawnString(temp, defaultStyles[i][0], &text);
  1052.         lengthRed = strlen(text);
  1053.         trap_SetConfigstring(CS_LIGHT_STYLES+((i+LS_STYLES_START)*3)+0, text);
  1054.  
  1055.         Com_sprintf(temp, sizeof(temp), "ls_%dg", i);
  1056.         G_SpawnString(temp, defaultStyles[i][1], &text);
  1057.         lengthGreen = strlen(text);
  1058.         trap_SetConfigstring(CS_LIGHT_STYLES+((i+LS_STYLES_START)*3)+1, text);
  1059.  
  1060.         Com_sprintf(temp, sizeof(temp), "ls_%db", i);
  1061.         G_SpawnString(temp, defaultStyles[i][2], &text);
  1062.         lengthBlue = strlen(text);
  1063.         trap_SetConfigstring(CS_LIGHT_STYLES+((i+LS_STYLES_START)*3)+2, text);
  1064.  
  1065.         if (lengthRed != lengthGreen || lengthGreen != lengthBlue)
  1066.         {
  1067.             Com_Error(ERR_DROP, "Style %d has inconsistent lengths: R %d, G %d, B %d", 
  1068.                 i, lengthRed, lengthGreen, lengthBlue);
  1069.         }
  1070.     }        
  1071. }
  1072.  
  1073.  
  1074. /*
  1075. ==============
  1076. G_SpawnEntitiesFromString
  1077.  
  1078. Parses textual entity definitions out of an entstring and spawns gentities.
  1079. ==============
  1080. */
  1081. void G_SpawnEntitiesFromString( qboolean inSubBSP ) 
  1082. {
  1083.     // allow calls to G_Spawn*()
  1084.     level.spawning = qtrue;
  1085.     level.numSpawnVars = 0;
  1086.  
  1087.     // the worldspawn is not an actual entity, but it still
  1088.     // has a "spawn" function to perform any global setup
  1089.     // needed by a level (setting configstrings or cvars, etc)
  1090.     if ( !G_ParseSpawnVars(inSubBSP) ) 
  1091.     {
  1092.         Com_Error( ERR_FATAL, "SpawnEntities: no entities" );
  1093.     }
  1094.     
  1095.     if (!inSubBSP)
  1096.     {
  1097.         SP_worldspawn();
  1098.     }
  1099.     else
  1100.     {
  1101.         // Skip this guy if its worldspawn fails
  1102.         if ( !SP_bsp_worldspawn() )
  1103.         {
  1104.             return;
  1105.         }
  1106.     }
  1107.  
  1108.     // parse ents
  1109.     while( G_ParseSpawnVars(inSubBSP) ) 
  1110.     {
  1111.         G_SpawnGEntityFromSpawnVars(inSubBSP);
  1112.     }    
  1113.  
  1114.     if (!inSubBSP)
  1115.     {
  1116.         level.spawning = qfalse;            // any future calls to G_Spawn*() will be errors
  1117.     }
  1118. }
  1119.  
  1120. /*QUAKED model_static (1 0 0) (-16 -16 -16) (16 16 16) NO_MP
  1121. "model"        arbitrary .md3 file to display
  1122. */
  1123. void SP_model_static ( gentity_t* ent )
  1124. {
  1125.     if (ent->spawnflags & 1)
  1126.     {    // NO_MULTIPLAYER
  1127.         G_FreeEntity( ent );
  1128.     }
  1129.  
  1130.     G_SetOrigin( ent, ent->s.origin );
  1131.     
  1132.     VectorCopy(ent->s.angles, ent->r.currentAngles);
  1133.     VectorCopy(ent->s.angles, ent->s.apos.trBase );
  1134.  
  1135.     VectorCopy( ent->s.origin, ent->s.pos.trBase );
  1136.     VectorCopy( ent->s.origin, ent->r.currentOrigin );
  1137.  
  1138.     ent->s.modelindex = G_ModelIndex( ent->model );
  1139.     ent->s.pos.trType = TR_STATIONARY;
  1140.     ent->s.apos.trTime = level.time;
  1141.  
  1142.     if (level.mBSPInstanceDepth)
  1143.     {    // this means that this guy will never be updated, moved, changed, etc.
  1144.         ent->s.eFlags = EF_PERMANENT;
  1145.     }
  1146.  
  1147.     trap_LinkEntity ( ent );
  1148. }
  1149.  
  1150.  
  1151.